<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 * @author   howe <howe1995@163.com>
 */

namespace App\Services;

use App\Cache\SocketRoom;
use App\Constant\Database\MessageEnum;
use App\Constant\TalkEventConstant;
use App\Model\Friend;

class SubscribeHandleService
{
    /**
     * 消息事件与回调事件绑定.
     *
     * @var array
     */
    public const EVENTS = [
        // 聊天消息事件
        TalkEventConstant::ACTION_SEND => 'onConsumeTalk',
        // 键盘输入事件
        TalkEventConstant::ACTION_KEYBOARD => 'onConsumeKeyboard',
        // 用户下线状态事件
        TalkEventConstant::ACTION_LOGOUT => 'onConsumeOnlineStatus',
        // 用户在线状态事件
        TalkEventConstant::ACTION_LOGIN => 'onConsumeOnlineStatus',
        // 点赞事件
        TalkEventConstant::ACTION_LIKE => 'onConsumeLike',
        // 评论事件
        TalkEventConstant::ACTION_COMMENT => 'onConsumeComment',
        // 聊天消息撤销通知
        TalkEventConstant::ACTION_REVOKE => 'onConsumeRevokeTalk',
        // 好友申请相关事件
        TalkEventConstant::ACTION_APPLY => 'onConsumeFriendApply',
    ];

    /**
     * @var SocketClientService
     */
    private $clientService;

    public function __construct(SocketClientService $clientService)
    {
        $this->clientService = $clientService;
    }

    /**
     * @param array $data 数据 ['who' => '','action' => '','data' => ''];
     */
    public function handle(array $data)
    {
        if (! isset($data['who'], $data['action'], $data['data'])) {
            logInfo('param_error', 'handle', json_encode($data));
            return;
        }

        if (isset(self::EVENTS[$data['action']])) {
            call_user_func([$this, self::EVENTS[$data['action']]], $data);
        }
    }

    /**
     * Note - 评论
     * DateTime 2024/12/20 19:19
     * User Admin.
     */
    public function onConsumeComment(array $data): void
    {
        $receiver_id = $data['data']['to_user'];
        $fds[] = $this->clientService->findUserFds($receiver_id);

        if (empty($fds)) {
            return;
        }
        $fds = array_unique(array_merge(...$fds));
        // 客户端ID去重
        if (! $fds) {
            return;
        }
        $this->push($fds, $this->toJson($data));
    }

    /**
     * Note - 点赞
     * DateTime 2024/12/20 19:19
     * User Admin.
     */
    public function onConsumeLike(array $data): void
    {
        $receiver_id = $data['data']['to_user'];
        $fds[] = $this->clientService->findUserFds($receiver_id);

        if (empty($fds)) {
            return;
        }
        $fds = array_unique(array_merge(...$fds));
        // 客户端ID去重
        if (! $fds) {
            return;
        }
        $this->push($fds, $this->toJson($data));
    }

    /**
     * 对话聊天消息.
     *
     * @param array $data 队列消息
     */
    public function onConsumeTalk(array $data): void
    {
        $talk_type = $data['data']['is_group'];
        $sender_id = $data['data']['from_user'];
        $receiver_id = $data['data']['to_user'];
        $fds = [];

        if ($talk_type == MessageEnum::PRIVATE) {
            // $fds[] = $this->clientService->findUserFds($sender_id);
            $fds[] = $this->clientService->findUserFds($receiver_id);
        } elseif ($talk_type == MessageEnum::GROUP) {
            foreach (SocketRoom::getInstance()->getRoomMembers(strval($receiver_id)) as $uid) {
                if ($uid == $sender_id) {
                    continue;
                }
                $fds[] = $this->clientService->findUserFds(intval($uid));
            }
        }
        if (empty($fds)) {
            return;
        }
        $fds = array_unique(array_merge(...$fds));
        // 客户端ID去重
        if (! $fds) {
            return;
        }
        $this->push($fds, $this->toJson($data));
    }

    /**
     * 键盘输入事件消息.
     *
     * @param array $data 队列消息
     */
    public function onConsumeKeyboard(array $data): void
    {
    }

    /**
     * 用户上线或下线消息.
     * @param array $data 队列消息
     */
    public function onConsumeOnlineStatus(array $data): void
    {
        $user_id = (int) $data['data']['from'];

        // 获取好友id列表
        $ids = Friend::findAllFriendIds($user_id);
        if (empty($ids)) {
            return;
        }
        $fds = [];
        foreach ($ids as $friend_id) {
            $fds[] = $this->clientService->findUserFds(intval($friend_id));
        }
        $fds = array_unique(array_merge(...$fds));
        $this->push($fds, $this->toJson($data));
    }

    /**
     * 撤销聊天消息.
     *
     * @param array $data 队列消息
     */
    public function onConsumeRevokeTalk(array $data): void
    {
    }

    /**
     * 好友申请消息.
     *
     * @param array $data 队列消息
     */
    public function onConsumeFriendApply(array $data): void
    {
        $receiver_id = $data['data']['to_user'];
        $fds[] = $this->clientService->findUserFds($receiver_id);

        if (empty($fds)) {
            return;
        }
        $fds = array_unique(array_merge(...$fds));
        // 客户端ID去重
        if (! $fds) {
            return;
        }
        $this->push($fds, $this->toJson($data));
    }

    private function toJson(array $data): string
    {
        return json_encode($data, JSON_UNESCAPED_UNICODE);
    }

    /**
     * WebSocket 消息推送
     */
    private function push(array $fds, string $message): void
    {
        $server = server();
        foreach ($fds as $fd) {
            $server->exist(intval($fd)) && $server->push(intval($fd), $message);
        }
    }
}
